/*
File:		RepairBot.cpp
Author:		Ben Feldmann
Purpose:	Class to manage game RepairBot enemies
*/

#include "RepairBot.h"
#include "Event.h"
#include "SGD Wrappers/CSGD_TextureManager.h"
#include "SGD Wrappers/CSGD_Direct3D.h"
#include "SGD Wrappers\CSGD_XAudio2.h"
#include "EventSystem.h"
#include "MessageSystem.h"
#include "DestroyEntityMessage.h"
#include "CreatePickUpMessage.h"
#include "GamePlayState.h"
#include "Game.h"
#include "DungeonGenerator.h"
#include "Room.h"
#include "Level.h"
#include "Tile.h"


RepairBot::RepairBot() : target(nullptr), healme(nullptr)
{
	type = OBJ_ENEMY;

	int randParts = rand() % 2 + 1;

	SetMetal(randParts);
	SetCircuitry(randParts);

	SetHealth(150.0f);
	SetDifficulty(3);
	SetWidth(32);
	SetHeight(32);

	SetPrevX(GetX()); 
	SetPrevY(GetY());
	SetCollided(false);
	SetAttackTimer(0);

	SetSpeed(32);

	SetTextureID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Graphics/Dummy Images/repairEnemy.png")));

	EventSystem::GetInstance()->RegisterClient("target_hit", this);

	maxHealth = (int)GetHealth();

	//CSGD_XAudio2::GetInstance()->SFXPlaySound(moveSound, true);
}

RepairBot::~RepairBot() 
{	
	if(GetTextureID() != -1 )
	{
		CSGD_TextureManager::GetInstance()->UnloadTexture(GetTextureID());
		SetTextureID(-1);
	}

	EventSystem::GetInstance()->UnregisterClientAll(this);

	if( target )
		target->Release();
	if( healme )
		healme->Release();
}

void RepairBot::Update(float elapsed) 
{
	int camx = GamePlayState::GetInstance()->GetCamX();
	int camy = GamePlayState::GetInstance()->GetCamY();
	if( GetX() > camx + 800 || GetX() + GetWidth() < camx || GetY() + GetHeight() < camy || GetY() > camy + 600 )
	{
		return;
	}

	if(!repairer.IsPlaying())
		repairer.Play();

	Enemy::Update(elapsed);

	// Health over max?
	if(GetHealth() > maxHealth)
		SetHealth((float)maxHealth);

	if(GetHealth() <= 0)
	{
		CreatePickUpMessage* msg1 = new CreatePickUpMessage(0, GetMetal(), GetVectorPos(), GetType());
		MessageSystem::GetInstance()->SendMsg(msg1);
		msg1 = nullptr;

		int x = GetCircuitry();

		CreatePickUpMessage* msg2 = new CreatePickUpMessage(1, GetCircuitry(), GetVectorPos(), GetType());
		MessageSystem::GetInstance()->SendMsg(msg2);
		msg2 = nullptr;

		DestroyEntityMessage* msg = new DestroyEntityMessage(this);
		MessageSystem::GetInstance()->SendMsg(msg);
		msg = nullptr;

		return;
	}

	if(disabled == true)
		return;

	repairer.Update(elapsed);

	if(healme)
		healme->Release();
	healme = nullptr;

	if( target )
		target->Release();
	target = nullptr;


	// Get target player
	if(GamePlayState::GetInstance()->GetPlayer2() != nullptr)
	{
		float p1distance = -1, p2distance = -1;
		float p1x = -1, p2x = -1;
		float p1y = -1, p2y = -1;

		p1x = (GamePlayState::GetInstance()->GetPlayer()->GetX()-GetX())*(GamePlayState::GetInstance()->GetPlayer()->GetX()-GetX());
		p1y = (GamePlayState::GetInstance()->GetPlayer()->GetY()-GetY())*(GamePlayState::GetInstance()->GetPlayer()->GetY()-GetY());
		p1distance = sqrtf(p1x+p1y);

		p2x = (GamePlayState::GetInstance()->GetPlayer2()->GetX()-GetX())*(GamePlayState::GetInstance()->GetPlayer2()->GetX()-GetX());
		p2y = (GamePlayState::GetInstance()->GetPlayer2()->GetY()-GetY())*(GamePlayState::GetInstance()->GetPlayer2()->GetY()-GetY());
		p2distance = sqrtf(p2x+p2y);

		if(p1distance <= p2distance)
			target = GamePlayState::GetInstance()->GetPlayer();
		else
			target = GamePlayState::GetInstance()->GetPlayer2();
	}
	else
		target = GamePlayState::GetInstance()->GetPlayer();

	if( target )
		target->AddRef();
	else
		return;

	if(target->GetRoomNum() != GetRoomNum())
		return;


	// Movement

	bool left = false;
	bool right = false;
	bool up = false;
	bool down = false;

	if(target->GetX() > GetX() + GetWidth())
		right = true;
	else
		left = true;

	if(target->GetY() > GetY() + GetHeight())
		down = true;
	else
		up = true;
	
	// Back up
	if(target->GetX() - 100 < GetX() && right)
	{
		if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(moveSound))
			CSGD_XAudio2::GetInstance()->SFXPlaySound(moveSound);
		SetX(GetX() - GetSpeed() * elapsed);
	}
	
	// Back up
	else if(target->GetX() + 100 > GetX() && left)
	{
		if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(moveSound))
			CSGD_XAudio2::GetInstance()->SFXPlaySound(moveSound);
		SetX(GetX() + GetSpeed() * elapsed);
	}
	
	// Back up
	if(target->GetY() + 100 > GetY() && up)
	{
		if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(moveSound))
			CSGD_XAudio2::GetInstance()->SFXPlaySound(moveSound);
		SetY(GetY() + GetSpeed() * elapsed);
	}
	
	// Back up
	else if(target->GetY() - 100 < GetY() && down)
	{
		if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(moveSound))
			CSGD_XAudio2::GetInstance()->SFXPlaySound(moveSound);
		SetY(GetY() - GetSpeed() * elapsed);
	}

	std::vector<Enemy*> roomEnemies;

	// Get all the enemies onscreen
	if(target->GetRoomNum() != -1)
		roomEnemies = GamePlayState::GetInstance()->GetLevel()->GetRoom(target->GetRoomNum())->GetEnemyVec();
	else
		return;

	if(roomEnemies.size() == 0)
		return;

	// Get enemy to heal
	for(unsigned int i = 0; i < roomEnemies.size(); ++i)
		if(roomEnemies[i] != this)
		{
			if(healme == nullptr)
				healme = roomEnemies[i];
			if(roomEnemies[i]->GetHealth() <= healme->GetHealth() && healme != nullptr)
				healme = roomEnemies[i];

			healme->AddRef();
		}


	// Heal target
	SetAttackTimer(GetAttackTimer()+(1.0f*elapsed));
	if(GetAttackTimer() > 1.0f)
	{
		Attack();
	}

	if(GetCollided() == false)
	{
		SetPrevX(GetX());
		SetPrevY(GetY());
	}
	SetCollided(false);
}

void RepairBot::Render() 
{
	int camx = GamePlayState::GetInstance()->GetCamX();
	int camy = GamePlayState::GetInstance()->GetCamY();
	if( GetX() > camx + 800 || GetX() + GetWidth() < camx || GetY() + GetHeight() < camy || GetY() > camy + 600 )
	{
		return;
	}
	repairer.Render((int)GetX()- GamePlayState::GetInstance()->GetCamX(),(int)GetY()- GamePlayState::GetInstance()->GetCamY(),1.0f,D3DCOLOR_ARGB(255,255,255,255),false);
	if(healme != nullptr)
		CSGD_Direct3D::GetInstance()->DrawLine((int)GetX() + int(GetWidth()/2) - camx, (int)GetY() + int(GetHeight()/2) - camy,
		(int)healme->GetX() + int(GetWidth()/2) - camx, (int)healme->GetY() + int(GetHeight()/2) - camy, 255, 0, 0);

	Enemy::Render();
}

bool RepairBot::CheckCollision(IEntity* base) 
{
	if(Entity::CheckCollision(base) == true && base != this && base->GetType() != OBJ_WEAPON)
	{
		if(base->GetType() == OBJ_PLAYER)
		{
			SetX(GetPrevX()); 
			SetY(GetPrevY());

			if(base->GetRect().left <= GetRect().right)
				SetX(GetX()-1);
			else if(base->GetRect().right >= GetRect().left)
				SetX(GetX()+1);
			if(base->GetRect().bottom >= GetRect().top)
				SetY(GetY()+1);
			else if(base->GetRect().top <= GetRect().bottom)
				SetY(GetY()-1);

			SetCollided(true);
			return true;
		}
		if(base->GetType() == OBJ_ENEMY)
		{
			if(GetRect().left <= base->GetRect().left && GetRect().right <= base->GetRect().right && target->GetX() <= GetRect().left)
				SetX(GetPrevX());
			else if(GetRect().left >= base->GetRect().left && GetRect().right >= base->GetRect().right && target->GetX() <= GetRect().left)
			{
				SetX(GetX()+1);
			}
			else if(GetRect().left >= base->GetRect().left && GetRect().right >= base->GetRect().right && target->GetX() >= GetRect().right)
				SetX(GetPrevX());
			else if(GetRect().left <= base->GetRect().left && GetRect().right <= base->GetRect().right && target->GetX() >= GetRect().right)
			{
				SetX(GetX()-1);
			}

			if(GetRect().top >= base->GetRect().top && GetRect().bottom >= base->GetRect().bottom && target->GetY() <= GetRect().top)
				SetY(GetPrevY());
			else if(GetRect().top <= base->GetRect().top && GetRect().bottom <= base->GetRect().bottom && target->GetY() <= GetRect().top)
			{
				SetY(GetY()+1);
			}
			else if(GetRect().top >= base->GetRect().top && GetRect().bottom >= base->GetRect().bottom && target->GetY() >= GetRect().bottom)
				SetY(GetPrevY());
			else if(GetRect().top <= base->GetRect().top && GetRect().bottom <= base->GetRect().bottom && target->GetY() >= GetRect().bottom)
			{
				SetY(GetY()-1);
			}

			SetCollided(true);
			return true;
		}
		if(base->GetType() == OBJ_TILE && dynamic_cast<Tile*>(base)->GetSolid() == true)
		{
			SetX(GetPrevX()); 
			SetY(GetPrevY());

			if(base->GetRect().left <= GetRect().right)
				SetX(GetX()-1);
			else if(base->GetRect().right >= GetRect().left)
				SetX(GetX()+1);
			if(base->GetRect().bottom >= GetRect().top)
				SetY(GetY()+1);
			else if(base->GetRect().top <= GetRect().bottom)
				SetY(GetY()-1);

			SetCollided(true);
			return true;
		}
	}
	return false;
}

void RepairBot::Attack() 
{
	if( healme && healme->GetHealth() < healme->GetMax() )
	{
		if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(healSound))
			CSGD_XAudio2::GetInstance()->SFXPlaySound(healSound);

		healme->SetHealth(healme->GetHealth() + 10);
		SetAttackTimer(0.0f);
	}
}

void RepairBot::HandleEvent(Event* thisEvent)
{
	if(thisEvent->GetParameter() != this)
		return;

	if(thisEvent->GetEventID() == "target_hit" && GetHealth() > 0)
	{
		void* tmpPtr = thisEvent->GetParameter2();
		float* tmp = (float*)(tmpPtr);
		SetHealth(GetHealth() - *tmp);

		delete tmp;

		damageEm->Burst();
	}
}

RECT RepairBot::GetRect()
{
	if(repairer.GetFileName().c_str() != L"NONE")
	{
		RECT tmp = repairer.GetCollsionRect();
		int width = tmp.right;
		int height = tmp.bottom;
		tmp.top += (long)(GetY() - repairer.GetAPoint().fY + height);
		tmp.bottom = height + tmp.top;
		tmp.left += (long)(GetX() - repairer.GetAPoint().fX + (width/2));
		tmp.right = width + tmp.left;
		return tmp;
	}
	else
	{
		RECT tmp = {};
		return tmp;
	}
}